package services;


import java.io.IOException;
import java.net.InetAddress;
import java.util.LinkedList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;

import common.Encryption;
import common.Message;
import common.People;
import common.ServicePort;
import common.Tunnel;


public class IMService extends Service{
	enum Function
	{
		NullFunction,
		OpenP2P,
		Close,
		Message,
		Binary,
		OfflineMessage,
		UnnamedMessage
	}

	private static String imServiceAddress = "192.168.1.114";
	private static int imServicePort = ServicePort.IMService;
	private ReceivceHandler messageHandler = null;
	private P2PService p2pService = null;
	private int userID;
	
	public IMService(ReceivceHandler messageHandler, int id) throws Exception {
		super(imServiceAddress, imServicePort);
		userID = id;
		p2pService = new P2PService();
		this.messageHandler = messageHandler;
		
		openP2P();
	}

	public void finalize() throws Throwable {
		
	}

	private void openP2P() {
		try {
			boolean ret = false;
			JSONObject request = new JSONObject();
			request.put("Function",Function.OpenP2P.ordinal());
			request.put("ID", userID);
			
			JSONObject response = request(request);
			ret = response.getBoolean("Return");
		} catch(Exception e) {
			e.printStackTrace();			
		}
	}
	
	private void closeP2P() {
		try {
			boolean ret = false;
			
			JSONObject request = new JSONObject();
			request.put("Function",Function.Close.ordinal());
			request.put("ID", userID);
			
			JSONObject response;
			
			response = request(request);
			ret = response.getBoolean("Return");
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void close() {
		closeP2P();
		super.close();
	}
	
	public List<Message> offlineMessage() throws Exception {
		boolean ret = false;

		JSONObject request = new JSONObject();
		request.put("Function",Function.OfflineMessage.ordinal());
		request.put("ID", userID);
		
		JSONObject response = request(request);
		ret = response.getBoolean("Return");
		
		List<Message> messages = new LinkedList<Message>();
		
		if(ret) {
			JSONArray jsonMessages = response.getJSONArray("Messages");
			
			for(int i = 0;i < jsonMessages.length();i++) {
				JSONObject obj = (JSONObject) jsonMessages.get(i);
				Message message = new Message();
				message.id = obj.getLong("ID");
				message.form = obj.getLong("Form_Users_ID");
				message.to = obj.getLong("To_Users_ID");
				message.message = obj.getString("Message");
				message.time = obj.getLong("Time");

				messages.add(message);	
			}
		}
		
		return messages;
	}
	
	/**
	 * 
	 * @param message
	 * @param to
	 * @throws IOException 
	 * @throws  
	 */
	public boolean send(String message, People to) throws Exception{
		boolean ret = false;
		
		JSONObject request = new JSONObject();
		request.put("Function",Function.Message.ordinal());
		request.put("Message", message);
		request.put("To", to.account);
		request.put("Form", userID);
		
		Tunnel t = p2pService.getTunnel(to);
		
		JSONObject response = null;
		
		if(t == null) {
			response = request(request,t);
		} 
		else {
			response = request(request);
		}
			
		ret = response.getBoolean("Return");

		return ret;
	}

	public boolean send(byte[] binary, People to) throws Exception {
		String message = Encryption.toBase64(binary);
		
		boolean ret = false;
		
		JSONObject request = new JSONObject();
		request.put("Function",Function.Binary.ordinal());
		request.put("Binary", message);
		request.put("To", to.account);
		request.put("Form", userID);
		
		Tunnel t = p2pService.getTunnel(to);
		
		JSONObject response = request(request,t);
		ret = response.getBoolean("Return");

		return ret;
	}
	
	/**
	 * 
	 * @param message
	 * @param to
	 * @throws Exception 
	 */
	public boolean unnamedSend(String message, People to) throws Exception{

		boolean ret = false;
		
		JSONObject request = new JSONObject();
		request.put("Function",Function.UnnamedMessage.ordinal());
		request.put("Message", message);
		request.put("To", to.account);
		request.put("From", userID);
		
		Tunnel t = p2pService.getTunnel(to);
		
		JSONObject response = request(request,t);
		ret = response.getBoolean("Return");
		
		return ret;
	}
	
	@Override
	public void receivedFromClient(JSONObject request, InetAddress address, int port) throws IOException {
		super.receivedFromClient(request, address, port);
		
		Function type = (Function)request.get("Function");
		int from = request.getInt("From");
		
		if(messageHandler == null) 
			return;
		
		switch(type) {
		case Message:
			messageHandler.messageHandler(request.getString("Message"), from);
			break;
		case Binary:
			messageHandler.binaryHandler(Encryption.fromBase64(request.getString("Binary")),from);
			break;
		case UnnamedMessage:
			messageHandler.unnamedMessageHandler(request.getString("Message"),from);
			break;
		default:
			break;
		}
	}

	/**
	 * 
	 * @param callback
	 */
	public void setReceivce(ReceivceHandler callback) {
		messageHandler = callback;
	}
}
